let script = document.createElement("script");
script.type = "text/javascript";
script.src = "/resources/js/axios.js";
document.getElementsByTagName('head')[0].appendChild(script);
/** web连接 */
let websocket = null;
/** webUrl */
let webSocketUrl = "";
/** 心跳时间：一秒 */
let timeout =  1000;
/** 心跳定时对象 */
let heartTimeoutObj = null;
/** 服务器定时对象 */
let serverTimeoutObj = null;
/** 重新连接定时对象 */
let reConnectTimeoutObj = null;
/** 重新连接锁 */
let reConnectLock = false;
/** 获取消息成功的回调方法 */
var acMessageCallback = null;

/**
 * 封装AJAX Post请求
 * 增加请求头X-Requested-With，以便标识为Ajax请求；对后端拦截的响应做统一处理
 * 默认返回结果结构：{data:{flag, data, errorMsg}}
 *
 * @param url 请求地址
 * @param data 数据
 * @param successCallback 执行成功的回调方法，参数returnData为后台返回数据
 * @param failCallback 执行失败的回调方法，参数returnData为后台返回数据
 * @param errorCallback 出错的回调方法，参数error为异常数据
 *
 * @return {boolean} 执行成功回调后，返回true，其他均返回false
 */
function ajaxPostPackage(url, data, successCallback, failCallback, errorCallback) {
    return axios.post(url, data, {headers: {'X-Requested-With': 'XMLHttpRequest'}})
        .then(result => {
            let returnData = result.data;
            if(returnData.flag){
                successCallback(returnData);
                return true;
            }else{
                failCallback(returnData);
                return false;
            }
        })
        .catch(error => {
            //获取响应头
            let response = error.response;
            if (typeof(response) != "undefined") {
                let headers = response.headers;
                //获取转发标志和转发地址
                let redirect = headers.redirect;
                let contentPath = decodeURIComponent(headers['contentpath']);
                //跳转至服务器指定的路径
                if (redirect == "REDIRECT") {
                    window.top.location.href = contentPath;
                    return false;
                }
            }
            errorCallback(error);
            return false;
        });
};

/**
 * 封装AJAX Get请求
 * 增加请求头X-Requested-With，以便标识为Ajax请求；对后端拦截的响应做统一处理
 * 默认返回结果结构：{data:{flag, data, errorMsg}}
 *
 * @param url 请求地址
 * @param successCallback 执行成功的回调方法，参数returnData为后台返回数据
 * @param failCallback 执行失败的回调方法，参数returnData为后台返回数据
 * @param errorCallback 出错的回调方法，参数error为异常数据
 *
 * @return {boolean} 执行成功回调后，返回true，其他均返回false
 */
function ajaxGetPackage(url, successCallback, failCallback, errorCallback) {
    return axios.get(url, {headers: {'X-Requested-With': 'XMLHttpRequest'}})
        .then(result => {
            let returnData = result.data;
            if(returnData.flag){
                successCallback(returnData);
                return true;
            }else{
                failCallback(returnData);
                return false;
            }
        })
        .catch(error => {
            //获取响应头
            let response = error.response;
            if (typeof(response) != "undefined") {
                let headers = response.headers;
                //获取转发标志和转发地址
                let redirect = headers.redirect;
                let contentPath = decodeURIComponent(headers['contentpath']);
                //跳转至服务器指定的路径
                if (redirect == "REDIRECT") {
                    window.top.location.href = contentPath;
                    return false;
                }
            }
            errorCallback(error);
            return false;
        });
};

/**
 * 日期格式化
 * 调用：new Date().dateFormatString(格式化字符串)
 *
 * @param dataFormat 格式化字符串：y年，M月份，d日，H小时，m分钟，s秒，S毫秒，例如yyyyMMdd HH:mm:ss:S
 *
 * @returns {string} 格式化后的日期字符串
 */
Date.prototype.dateFormatString = function (dataFormat) {
    //格式化的每个字段
    let formatRegular = {
        //月份
        "M+": this.getMonth() + 1,
        //日
        "d+": this.getDate(),
        //小时
        "H+": this.getHours(),
        //分
        "m+": this.getMinutes(),
        //秒
        "s+": this.getSeconds(),
        //毫秒
        "S": this.getMilliseconds()
    };
    //格式化年份
    if (/(y+)/.test(dataFormat)) {
        dataFormat = dataFormat.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
    }
    //格式化其他字段
    for (let node in formatRegular) {
        if (new RegExp("(" + node + ")").test(dataFormat)) {
            dataFormat = dataFormat.replace(RegExp.$1, (RegExp.$1.length == 1) ? (formatRegular[node]) : (("00" + formatRegular[node]).substr(("" + formatRegular[node]).length)));
        }
    }
    return dataFormat;
};

/**
 * 删除数组指定元素
 * @param node 要删除的元素
 * @returns {boolean} 删除成功，返回true
 */
Array.prototype.remove = function (node) {
    let index = this.indexOf(node);
    if (index > -1) {
        this.splice(index, 1);
        return true;
    } else {
        return false;
    }
}

/**
 * 数组不影响原数组的排序
 * @returns {null|*[]|{}}
 */
Array.prototype.sortNoAffect = function () {
    let sortArray = clone(this);
    sortArray.sort();
    return sortArray;
}

/**
 * 克隆对象，防止引用类型变量赋值后会与原对象共用一个地址
 * @param objectParam 要克隆的对象
 * @returns {null|[]|{}} 返回克隆后的数组、对象，传入空值，则返回空
 */
function clone (objectParam) {
    let nodeObject;
    if (typeof objectParam == "object") {
        if (objectParam === null) {
            nodeObject = null;
        } else {
            if (objectParam instanceof Array) {
                nodeObject = [];
                for (let i = 0, len = objectParam.length; i < len; i++) {
                    nodeObject.push(clone(objectParam[i]));
                }
            } else {
                nodeObject = {};
                for (let subNode in objectParam) {
                    nodeObject[subNode] = clone(objectParam[subNode]);
                }
            }
        }
    } else {
        nodeObject = objectParam;
    }
    return nodeObject;
}

/**
 * 初始化双向连接
 * @param url 后端连接地址
 * @param callback 收到消息后的回调，参数为返回的消息
 */
function initWebSocket(url, callback) {
    this.webSocketUrl = url;
    this.acMessageCallback = callback;
    this.webSocket = new WebSocket(url);
    // 连接成功
    this.webSocket.onopen = onOpenMessageCallback;
    // 连接错误
    this.webSocket.onerror = onErrorMessageCallback;
    // 收到消息的回调
    this.webSocket.onmessage = onMessageCallback;
    // 连接关闭的回调
    this.webSocket.onclose = onCloseMessageCallback;
    // 监听窗口关闭事件，当窗口关闭时，主动去关闭websocket连接，防止连接还没断开就关闭窗口，server端会抛异常。
    window.onbeforeunload = onbeforeunloadCallback;
}

/**
 * 连接成功后的回调
 */
function onOpenMessageCallback() {
    //开启心跳
    startHeart();
    console.log("WebSocket连接成功！状态码：" + webSocket.readyState);
}

/**
 * 连接失败后的回调
 */
function onErrorMessageCallback() {
    //重连
    reConnect();
    console.log("WebSocket连接发生错误！状态码：" + webSocket.readyState)
}

/**
 * 心跳开启
 */
function startHeart() {
    //1、清空定时器
    if (heartTimeoutObj != null) {
        clearTimeout(heartTimeoutObj);
    }
    if (serverTimeoutObj != null) {
        clearTimeout(serverTimeoutObj);
    }

    //2、设置心跳定时器
    heartTimeoutObj = setTimeout(() => {
        //发送心跳信息至后端，若连接失败，则进行重连
        if (webSocket && webSocket.readyState == 1) {
            webSocket.send("heartbeat");
        } else {
            reConnect();
            return;
        }

        //设置服务器超时判断定时器：若服务器超时未回应，则关闭连接
        serverTimeoutObj = setTimeout(() => {
            //关闭连接
            webSocket.close();
        }, timeout);
    }, timeout)
}

/**
 * 收到信息后的回调
 * @param event 收到的信息
 */
function onMessageCallback (event) {
    let message = JSON.parse(event.data);
    //重置心跳
    resetHeart();
    //执行原方法传入的回调
    acMessageCallback(message);
}

/**
 * 心跳重置
 */
function resetHeart() {
    //清除定时器
    clearTimeout(heartTimeoutObj);
    clearTimeout(serverTimeoutObj);

    // 重启心跳
    startHeart();
}

/**
 * 连接关闭后的回调
 */
function onCloseMessageCallback() {
    //重新连接
    reConnect();
    console.log( "WebSocket连接关闭！状态码：" + this.webSocket.readyState)
}

/**
 * 重新连接
 */
function reConnect() {
    //若已有进程在执行，则返回
    if(reConnectLock){
        return;
    }

    console.log("即将重新连接……");
    reConnectLock = true;

    //没连接上会一直重连，设置延迟避免请求过多
    if (reConnectTimeoutObj != null) {
        clearTimeout(reConnectTimeoutObj);
    };
    reConnectTimeoutObj = setTimeout(() => {
        //新连接
        initWebSocket(webSocketUrl);
        reConnectLock = false;
    }, 5000);
}

/**
 * 刷新/跳转窗口前的回调方法
 */
function onbeforeunloadCallback() {
    webSocket.close()
}